package org.reborn.math

import scala.math
import scala.collection.{Seq}

case class VectorF(val length:Int){
  private val vec:Array[Float] = new Array(length)
  
  def apply(pos:Int):Float = { vec(pos) }
  def update(pos:Int,value:Float){ vec(pos) = value }
  
  def +(o:VectorF):VectorF = {VectorF((vec,o.vec).zipped.map(_+_))}
  def -(o:VectorF):VectorF = {VectorF((vec,o.vec).zipped.map(_-_))}
  def *(scalar:Float):VectorF = {VectorF(vec.map(_*scalar))}
  def /(scalar:Float):VectorF = {VectorF(vec.map(_/scalar))}
  def dot(o:VectorF):Float = {(vec,o.vec).zipped.map(_*_).reduceLeft(_+_)}
  def cross(o:VectorF):VectorF = {
	val x = this.vec(1) * o.vec(2) - this.vec(2) * o.vec(1)
	val y = this.vec(2) * o.vec(0) - this.vec(0) * o.vec(2)
	val z = this.vec(0) * o.vec(1) - this.vec(1) * o.vec(0)
	VectorF(List(x,y,z))
  }
  
  def magnitude():Float = {
    val sumOfSquares = vec.map((x)=>{x*x}).reduceLeft(_+_) 
    math.sqrt(sumOfSquares).asInstanceOf[Float]
  }
  def normalize():VectorF = { this / this.magnitude}
  
  override def equals(o:Any):Boolean = {
    o match{
      case v:VectorF => length == v.length && vec.corresponds(v.vec)(_ == _)
      case _ => false
    }
  }
  
  override def hashCode():Int = vec.hashCode
  
  def toArray = vec.clone
  
  def ofLength(length:Int,padVal:Float = 0.0f):VectorF = {
	if(this.length == length)
	  return this
	  
	val newVec = new Array[Float](length)
	
	for(i <- 0 until length){
      newVec(i) = if(i < this.length) vec(i) else padVal 
	}
	
	VectorF(newVec)
  }
  
  override def toString():String = {
	val sb = new StringBuilder
	vec.addString(sb,"<",", ",">")
	return sb.toString
  }
}

object VectorF{
  def apply(vec:Seq[Float]):VectorF = {
	val newVec = new VectorF(vec.size)
	var i = 0
	while(i < vec.size){
	  newVec.vec(i) = vec(i)
	  i += 1
	}
	
	newVec
  }
  
  def apply(arg0:Float, vec:Float*):VectorF = {
	val newVec = new VectorF(vec.size + 1)
	newVec(0) = arg0
	var i = 0
	while(i < vec.size){
	  newVec.vec(i+1) = vec(i)
	  i += 1
	}
	
	newVec
  }
}